package com.wn.trade.service.impl;
import com.wn.common.model.dto.trade.payback.AgencyBidPayDTO;
import com.wn.common.model.dto.trade.payback.BorrowRecordPayDTO;

import com.google.common.collect.Lists;

import java.util.Date;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wn.access.api.BankAccessApi;

import com.wn.common.exception.Assert;
import com.wn.common.model.dto.trade.bid.AgencyBidDTO;

import com.wn.common.model.dto.trade.bid.BankBidDTO;
import com.wn.common.model.dto.trade.bid.BidBalanceDTO;

import com.wn.common.model.dto.trade.bid.BorrowRecordStatusDTO;
import com.wn.common.model.dto.trade.payback.PayBackDTO;
import com.wn.common.model.vo.trade.bid.AgencyBidVo;
import com.wn.common.model.vo.trade.bid.LoanDetailVo;
import com.wn.common.model.vo.trade.bid.LoanVo;
import com.wn.common.model.vo.user.TokenVo;
import com.wn.common.model.vo.user.UserInfoVo;
import com.wn.common.result.Result;

import com.wn.common.result.enums.impl.BusinessCode;
import com.wn.common.utils.CalculateExpectUtil;
import com.wn.common.utils.GeneratorCodeUtil;
import com.wn.common.utils.TokenUtils;
import com.wn.pay.api.PayBankApi;
import com.wn.system.api.UserApi;
import com.wn.trade.entity.AgencyBid;
import com.wn.trade.entity.BorrowRecord;
import com.wn.trade.mapper.AgencyBidMapper;
import com.wn.trade.service.IAgencyBidService;
import com.wn.trade.service.IBorrowRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author yellow Docter
 * @date 2023 -03-04
 * @desc
 */
@Service
@Slf4j
public class AgencyBidServiceImpl extends ServiceImpl<AgencyBidMapper, AgencyBid>
        implements IAgencyBidService {

    @Autowired
    private UserApi userApi;

    @Autowired
    private BankAccessApi bankAccessApi;

    @Autowired
    private PayBankApi payBankApi;

    @Autowired
    private IBorrowRecordService borrowRecordService;

    @Override
    public AgencyBidVo addAgencyBidRecord(AgencyBidDTO agencyBidDTO) {

        //01  查询余额  (查询银行卡余额)
        //拿取手机号
        TokenVo tokenVo = TokenUtils.getTokenVo();
        String phone = tokenVo.getPhone();
        //拿到用户信息
        UserInfoVo userInfoVo = userApi.findUserById(phone);
        String userCode = userInfoVo.getUserCode();
        Result<BidBalanceDTO> bidBalanceDTO = bankAccessApi.getBidBalance(userCode);

        log.info("机构的账号余额是:{}", bidBalanceDTO);

        //02 添加机构的认购记录
        BigDecimal balance = bidBalanceDTO.getData().getBalance();
        BorrowRecord borrowRecord = borrowRecordService.getById(agencyBidDTO.getBorrowRecordId());

        //自己认购的金额
        String amount = agencyBidDTO.getAmount();

        if (balance.compareTo(borrowRecord.getAmount()) < 0) {
            Assert.error(BusinessCode.BALANCE_NOT_ENOUGH);
        }

        AgencyBid agencyBid = this.save(borrowRecord, tokenVo, userInfoVo, amount);
        log.info("结构认证的投资标:{}", agencyBid);

        //03  调用托管  进行日志记录

        //把 需要进行日志记录的数据发送给 bankAccess 进行 日志记录
        BankBidDTO bankBidDTO = new BankBidDTO();

        //冻结金额 （投资人认购的金额）
        bankBidDTO.setAmount(new BigDecimal(amount));
        bankBidDTO.setReqCode(agencyBid.getReqCode());
        //投资人id
        bankBidDTO.setUserCode(userInfoVo.getUserCode());
        //业务类型
        bankBidDTO.setBizType("BID");
        bankBidDTO.setBorrowRecordNo(borrowRecord.getBorrowRecordNo());
        bankBidDTO.setId(agencyBid.getId());

        //发送 给 bankAccess  进入日志记录 (给银行发送数据)
        //修改  AgencyBid
        Result<String> baseResult = bankAccessApi.bankBidService(bankBidDTO);
        if (baseResult.getCode() == 200) { //成功
            agencyBid.setStatus(1);
            this.updateById(agencyBid);
            log.info("修改agencyBid的状态:{}", agencyBid);
        }
        //计算收益
        // 返回
        AgencyBidVo agencyBidVo = BeanUtil.copyProperties(agencyBid, AgencyBidVo.class);

        // 根据标的期限计算还款月数
        Double ceil = Math.ceil(borrowRecord.getPeriod() / 30.0);
        Integer month = ceil.intValue();
        // 计算预期收益
        BigDecimal expected = CalculateExpectUtil.getIncomeTotalInterest(
                new BigDecimal(agencyBidDTO.getAmount()),
                new BigDecimal("0.5"), //TODO 年化收益
                month);

        agencyBidVo.setExpectedIncome(expected);

        return agencyBidVo;
    }

    @Override
    public String borrowRecordStatus(Long borrowRecordId, String status, String commission) {

        //01  生成放款明细
        //拿到接口信息
        BorrowRecord borrowRecord = borrowRecordService.getById(borrowRecordId); // trade库下面的 borrow-record 表

        //拿到表
        //如果借款  不能有集合
//        AgencyBid agencyBid = this.getOne(Wrappers.lambdaQuery(AgencyBid.class)
//                .eq(AgencyBid::getBorrowRecordId, borrowRecord.getId()));

        //如果借款  不能有集合
        // trade库下面的 AgencyBid 表
        List<AgencyBid> agencyBids = this.list(Wrappers.lambdaQuery(AgencyBid.class)
                .eq(AgencyBid::getBorrowRecordId, borrowRecord.getId()));

        LoanVo loanVo = createLoanVo(borrowRecord, agencyBids, commission);
        //02 放款确认  (扣除投资人  转账到  借款的账号上去 )

        //进行远程调用 bankAccess 给 银行发送消息 进行转账操作
        Result<String> baseResult = bankAccessApi.confirmLoan(loanVo);

        log.info("银行放款通过====>{}",baseResult.getMessage());

        //03  状态的修改  （borrowRecord 借款状态 ）
        if (baseResult.getCode() == 200){
            //修改状态
            //修改   trade库下面的 AgencyBid 表的状态  BID_STATUS 字段
            updateAgencyBids(agencyBids);
        }else{
            //放款失败
            Assert.error(BusinessCode.BANK_STATUS_MODIFY_FAILED);
        }
//      借款的状态   borrowRecord (数据库状态修改  )            银行系统 (borrowRecord 状态修改 )
        BorrowRecordStatusDTO borrowRecordStatusDTO = new BorrowRecordStatusDTO();
        borrowRecordStatusDTO.setReqCode(borrowRecord.getReqCode());
        borrowRecordStatusDTO.setBorrowRecordNo(borrowRecord.getBorrowRecordNo());
        borrowRecordStatusDTO.setBorrowStatus(borrowRecord.getBorrowStatus());
        borrowRecordStatusDTO.setBorrowRecordId(borrowRecord.getId());

        Result<String> baseResultStatus = bankAccessApi.updateBorrowRecordStatus(borrowRecordStatusDTO);
        if (baseResultStatus.getCode() != 200){
            //修改状态
            Assert.error(BusinessCode.BANK_STATUS_MODIFY_FAILED);
        }

        //修改 借款状态
        // trade库下面的 borrow-record 表 中的  BORROW_STATUS 字段
        borrowRecord.setBorrowStatus("REPAYING");
        borrowRecordService.updateById(borrowRecord);
        log.info("借款记录修改状态");

        //生成 还款计划
        PayBackDTO payBackDTO = new PayBackDTO();

        //还款 需要的  dto
        BorrowRecordPayDTO borrowRecordPayDTO = BeanUtil.copyProperties(borrowRecord, BorrowRecordPayDTO.class);
        payBackDTO.setBorrowRecordPayDTO(borrowRecordPayDTO);

        //还款 需要的  dto
        List<AgencyBidPayDTO> agencyBidPayDTOS = BeanUtil.copyToList(agencyBids, AgencyBidPayDTO.class);
        payBackDTO.setAgencyBids(agencyBidPayDTOS);

        // 利率
        payBackDTO.setInvestorAnnualRate(new BigDecimal("0.02"));
        payBackDTO.setBorrowerAnnualRate(new BigDecimal("0.02"));
        //生成 还款计划
        Result<String> result = payBankApi.payPlan(payBackDTO);

        if (result.getCode() != 200){
            //修改状态
            Assert.error(BusinessCode.BANK_STATUS_MODIFY_FAILED);
        }

        return "审核通过";
    }

    private void updateAgencyBids(List<AgencyBid> agencyBids) {
        //修改标的状态
        agencyBids.forEach(agencyBid -> {
            agencyBid.setBidStatus("LOAN");
             updateById(agencyBid);
        });
    }

    /**
     * 创建  放款明细
     *
     * @param borrowRecord
     * @param agencyBids
     * @param commission
     * @return
     */
    private LoanVo createLoanVo(BorrowRecord borrowRecord, List<AgencyBid> agencyBids, String commission) {

        LoanVo loanVo = new LoanVo();

        //一个  借款id下面有多个  标  (需要把标转成 LoanDetailVo 对象  )
        List<LoanDetailVo> loanDetailVos = agencyBids.stream().map(agencyBid -> {
            LoanDetailVo loanDetailVo = new LoanDetailVo();
            loanDetailVo.setAmount(agencyBid.getAmount());
            loanDetailVo.setPreReqCode(agencyBid.getReqCode());
            return loanDetailVo;
        }).collect(Collectors.toList());

        loanVo.setDetails(loanDetailVos);

        loanVo.setCommission(new BigDecimal(commission));
        loanVo.setBorrowRecordNo(borrowRecord.getBorrowRecordNo());
        loanVo.setReqCode(GeneratorCodeUtil.generator("LOAN"));

        loanVo.setId(borrowRecord.getId());

        return loanVo;

    }

    /**
     * 把认证的标  进行保存
     *
     * @param borrowRecord
     * @param tokenVo
     * @param userInfoVo
     * @param amount
     * @return
     */
    private AgencyBid save(BorrowRecord borrowRecord, TokenVo tokenVo, UserInfoVo userInfoVo, String amount) {

        AgencyBid agencyBid = new AgencyBid();

        //用户信息
        agencyBid.setUserId(Long.parseLong(tokenVo.getUserId()));
        //用户姓名
        agencyBid.setName(userInfoVo.getUserName());
        agencyBid.setUserCode(userInfoVo.getUserCode());

        //认购金额
        agencyBid.setAmount(new BigDecimal(amount));

        //状态 (冻结)
        agencyBid.setBidStatus("FROZEN");
        agencyBid.setCreateDate(new Date());
        agencyBid.setReqCode(GeneratorCodeUtil.generator("AGEN"));
        //可用状态
        agencyBid.setStatus(0);

        //借款记录
        agencyBid.setBorrowRecordId(borrowRecord.getId());
        agencyBid.setBorrowRecordNo(borrowRecord.getBorrowRecordNo());
        agencyBid.setBorrowRecordName(borrowRecord.getName());
        agencyBid.setBorrowRecordPeriod(borrowRecord.getPeriod());
        //投资年化利率-冗余字段
        agencyBid.setInvestRate(borrowRecord.getInvestRate());

        this.save(agencyBid);

        return agencyBid;
    }

}
